package com.example.tourpal.widget;

import com.example.tourpal.R;

import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

public class DynamicListView extends ListView implements OnScrollListener {
	private String pull_up = getResources().getString(R.string.pull_up);
	private String pull_down = getResources().getString(R.string.pull_down);
	private String ing = getResources().getString(R.string.ing);
	private String release = getResources().getString(R.string.release);
	private String refresh = getResources().getString(R.string.refresh);
	private String load = getResources().getString(R.string.load);

	public interface DynamicListViewListener {
		public boolean onRefreshOrMore(DynamicListView dynamicListView,
				boolean isRefresh);
	}

	enum RefreshStatus {
		None, Normal, Willrefresh, Refreshing
	}

	class StatusView extends LinearLayout {
		private String normal;
		private String willrefresh;
		private String refreshing;

		public int height;
		public int width;
		private ProgressBar progressBar = null;
		private TextView textView = null;

		private RefreshStatus currentStatus = RefreshStatus.None;

		public StatusView(Context context) {
			this(context, null);
			// TODO Auto-generated constructor stub
		}

		public StatusView(Context context, AttributeSet attrs) {
			this(context, attrs, 0);
			// TODO Auto-generated constructor stub
		}

		@SuppressLint("NewApi")
		public StatusView(Context context, AttributeSet attrs, int defStyle) {
			super(context, attrs, defStyle);

			initStatusView(context);
		}

		private void initStatusView(Context context) {
			setGravity(Gravity.CENTER);

			progressBar = new ProgressBar(context);
			progressBar.setLayoutParams(new LinearLayout.LayoutParams(30, 30));

			textView = new TextView(context);
			textView.setPadding(5, 0, 0, 0);

			addView(progressBar);
			addView(textView);

			int w = View.MeasureSpec.makeMeasureSpec(0,
					View.MeasureSpec.UNSPECIFIED);
			int h = View.MeasureSpec.makeMeasureSpec(0,
					View.MeasureSpec.UNSPECIFIED);
			measure(w, h);

			height = getMeasuredHeight();
			width = getMeasuredWidth();

			setRefreshStatus(RefreshStatus.Normal);
		}

		private void setRefreshStatus(RefreshStatus status) {
			if (currentStatus != status) {
				currentStatus = status;
				if (status == RefreshStatus.Refreshing) {
					progressBar.setVisibility(View.VISIBLE);
				} else {
					progressBar.setVisibility(View.GONE);
				}
			}
			updateUI();
			invalidate();

		}

		private void updateUI() {
			switch (currentStatus) {
			case Normal:
				textView.setText(normal);
				progressBar.setProgress(0);
				break;
			case Willrefresh:
				textView.setText(willrefresh);
				break;
			case Refreshing:
				textView.setText(refreshing);
				break;
			default:
				break;
			}
		}

		public void setStatusStrings(String normalString,
				String willrefreshString, String refreshingString) {
			normal = normalString;
			willrefresh = willrefreshString;
			refreshing = refreshingString;
			updateUI();
		}
	}

	private StatusView refreshView;
	private StatusView moreView;

	private int itemFlag = -1;
	private boolean isRecorded = false;
	private int downY = -1;
	private final float minTimesToRefresh = 3.0f;
	private final static int ITEM_FLAG_FIRST = 1;
	private final static int ITEM_FLAG_NONE = 0;
	private final static int ITEM_FLAG_LAST = -1;

	private DynamicListViewListener onRefreshListener;
	private DynamicListViewListener onMoreListener;

	private boolean doMoreWhenBottom = false;

	public DynamicListView(Context context) {
		this(context, null);
		// TODO Auto-generated constructor stub
	}

	public DynamicListView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
		// TODO Auto-generated constructor stub
	}

	public DynamicListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context);
	}

	private void init(Context context) {
		refreshView = new StatusView(context);
		moreView = new StatusView(context);

		refreshView.setStatusStrings(pull_down + refresh, release + refresh,
				refresh + ing);
		moreView.setStatusStrings(pull_up + load, release + load, load + ing);

		addHeaderView(refreshView, null, false);
		addFooterView(moreView, null, false);
		setOnScrollListener(this);

		doneRefresh();
		doneMore();

	}

	private void doMore() {
		moreView.setRefreshStatus(RefreshStatus.Refreshing);
		moreView.setPadding(0, 0, 0, 0);
		if (onMoreListener.onRefreshOrMore(this, false))
			doneMore();
	}

	public void doneMore() {
		moreView.setRefreshStatus(RefreshStatus.Normal);
		moreView.setPadding(0, 0, 0, -1 * moreView.height);

	}

	private void doRefresh() {
		refreshView.setRefreshStatus(RefreshStatus.Refreshing);
		refreshView.setPadding(0, 0, 0, 0);
		if (onRefreshListener.onRefreshOrMore(this, true))
			doneRefresh();
	}

	public void doneRefresh() {
		refreshView.setRefreshStatus(RefreshStatus.Normal);
		refreshView.setPadding(0, -1 * refreshView.height, 0, 0);

	}

	@SuppressLint("ClickableViewAccessibility")
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			if (isRecorded == false
					&& (itemFlag == ITEM_FLAG_FIRST
							&& onRefreshListener != null
							&& refreshView.currentStatus == RefreshStatus.Normal || itemFlag == ITEM_FLAG_LAST
							&& onMoreListener != null
							&& moreView.currentStatus == RefreshStatus.Normal)) {
				downY = (int) ev.getY(0);
				isRecorded = true;
			}
			break;
		case MotionEvent.ACTION_UP:
			isRecorded = false;
			if (onRefreshListener != null
					&& refreshView.currentStatus == RefreshStatus.Willrefresh) {
				doRefresh();
			} else if (refreshView.currentStatus == RefreshStatus.Normal) {
				refreshView.setPadding(0, -1 * refreshView.height, 0, 0);
			}

			if (onMoreListener != null
					&& moreView.currentStatus == RefreshStatus.Willrefresh) {
				doMore();
			} else if (moreView.currentStatus == RefreshStatus.Normal) {
				moreView.setPadding(0, 0, 0, -1 * moreView.height);
			}
			break;
		case MotionEvent.ACTION_MOVE:
			if (isRecorded == false
					&& (itemFlag == ITEM_FLAG_FIRST
							&& onRefreshListener != null
							&& refreshView.currentStatus == RefreshStatus.Normal || itemFlag == ITEM_FLAG_LAST
							&& onMoreListener != null
							&& moreView.currentStatus == RefreshStatus.Normal)) {
				downY = (int) ev.getY(0);
				isRecorded = true;
			} else if (isRecorded) {
				int nowY = (int) ev.getY(0);
				int offset = nowY - downY;
				if (offset > 0 && itemFlag == ITEM_FLAG_FIRST) {
					setSelection(0);
					if (offset >= (minTimesToRefresh * refreshView.height * 1.5f)) {
						refreshView.setRefreshStatus(RefreshStatus.Willrefresh);
					} else {
						refreshView.setRefreshStatus(RefreshStatus.Normal);
					}
					refreshView.setPadding(0, -1
							* (refreshView.height - offset), 0, 0);
				} else if (itemFlag == ITEM_FLAG_LAST) {
					setSelection(getCount());
					if (offset <= -1
							* (minTimesToRefresh * moreView.height * 1.5f)) {
						moreView.setRefreshStatus(RefreshStatus.Willrefresh);
					} else {
						moreView.setRefreshStatus(RefreshStatus.Normal);
					}
					moreView.setPadding(0, 0, 0, -1
							* (moreView.height + offset));
				}
			}
			break;
		default:
			break;
		}
		return super.onTouchEvent(ev);
	}

	@Override
	public void onScroll(AbsListView v, int topItem, int visibleItemCnt,
			int totalItemCnt) {
		if (topItem == 0) {
			itemFlag = ITEM_FLAG_FIRST;
		} else if ((topItem + visibleItemCnt) == totalItemCnt) {
			itemFlag = ITEM_FLAG_LAST;
			if (doMoreWhenBottom && onMoreListener != null
					&& moreView.currentStatus != RefreshStatus.Refreshing) {
				doMore();
			}
		} else {
			itemFlag = ITEM_FLAG_NONE;
		}
	}

	@Override
	public void onScrollStateChanged(AbsListView arg0, int arg1) {
		// TODO Auto-generated method stub

	}

	public DynamicListViewListener getOnRefreshListener() {
		return onRefreshListener;
	}

	public void setOnRefreshListener(DynamicListViewListener onRefreshListener) {
		this.onRefreshListener = onRefreshListener;
	}

	public DynamicListViewListener getOnMoreListener() {
		return onMoreListener;
	}

	public void setOnMoreListener(DynamicListViewListener onMoreListener) {
		this.onMoreListener = onMoreListener;
	}

	public RefreshStatus getRefreshStatus() {
		return refreshView.currentStatus;
	}

	public RefreshStatus getMoreStatus() {
		return moreView.currentStatus;
	}

	public boolean isDoMoreWhenBottom() {
		return doMoreWhenBottom;
	}

	public void setDoMoreWhenBottom(boolean doMoreWhenBottom) {
		this.doMoreWhenBottom = doMoreWhenBottom;
	}

}
